from manimlib import *
import random as rd
#manim_sandbox出了点问题，所以我把要用的代码复制过来了
#注：这段为MATHEART_EVER和我是害羞的向量制作
class MyTriangle(Polygon):
    def get_side_length(self): # 三角形边长
        A, B, C = Polygon.get_vertices(self)

        a = math.sqrt((B[0]-C[0])**2 + (B[1]-C[1])**2)
        b = math.sqrt((A[0]-C[0])**2 + (A[1]-C[1])**2) 
        c = math.sqrt((A[0]-B[0])**2 + (A[1]-B[1])**2)

        return np.array([a,b,c])

    def get_three_angle(self): #三个角
        a, b, c = self.get_side_length()
        AngleA = math.acos((b**2 + c**2 - a**2) / (2 * b * c))
        AngleB = math.acos((a**2 + c**2 - b**2) / (2 * a * c))
        AngleC = math.acos((a**2 + b**2 - c**2) / (2 * a * b))
        return AngleA, AngleB, AngleC

    def get_circumference(self): # 周长
        a, b, c = self.get_side_length()
        return (a + b + c)

    def get_area(self): # 面积
        a, b, c = self.get_side_length()
        p = (a+b+c) / 2
        return math.sqrt(p*(p-a)*(p-b)*(p-c))

    def get_orthocenter(self): # 垂心坐标
        A, B, C = Polygon.get_vertices(self)
        a, b, c = self.get_side_length()
        AngleA, AngleB, AngleC = self.get_three_angle()
        Ax, Ay = A[0], A[1]
        Bx, By = B[0], B[1]
        Cx, Cy = C[0], C[1]

        xup = a / math.cos(AngleA) * Ax + b / math.cos(AngleB) * Bx + c / math.cos(AngleC) * Cx
        yup = a / math.cos(AngleA) * Ay + b / math.cos(AngleB) * By + c/ math.cos(AngleC) * Cy
        down = a / math.cos(AngleA) + b / math.cos(AngleB) + c / math.cos(AngleC)
        return np.array([xup/down,yup/down,0])

    def get_centroid(self): # 重心坐标
        A, B, C = Polygon.get_vertices(self)
        Ax, Ay = A[0], A[1]
        Bx, By = B[0], B[1]
        Cx, Cy = C[0], C[1]
        return np.array([(Ax + Bx + Cx) / 3, (Ay + By + Cy) / 3, 0])

    def get_circumcenter(self): # 外心坐标
        A, B, C = Polygon.get_vertices(self)
        AngleA, AngleB, AngleC = self.get_three_angle()
        Ax, Ay = A[0], A[1]
        Bx, By = B[0], B[1]
        Cx, Cy = C[0], C[1]

        xup = Ax * math.sin(2 * AngleA) + Bx * math.sin(2 * AngleB) + Cx * math.sin(2 * AngleC)
        yup = Ay * math.sin(2 * AngleA) + By * math.sin(2 * AngleB) + Cy * math.sin(2 * AngleC)
        down = math.sin(2 * AngleA) + math.sin(2 * AngleB) + math.sin(2 * AngleC) 
        return np.array([xup/down, yup/down, 0])

    def get_incenter(self): # 内心坐标
        A, B, C = Polygon.get_vertices(self)
        a, b, c = self.get_side_length()
        Ax, Ay = A[0], A[1]
        Bx, By = B[0], B[1]
        Cx, Cy = C[0], C[1]

        x = (a * Ax + b * Bx + c * Cx) / (a + b + c)
        y = (a * Ay + b * By + c * Cy) / (a + b + c)

        return np.array([x, y, 0])

    def get_excenter(self): # 旁心坐标
        A, B, C = Polygon.get_vertices(self)
        a, b, c = self.get_side_length()
        Ax, Ay = A[0], A[1]
        Bx, By = B[0], B[1]
        Cx, Cy = C[0], C[1]

        Ja_x = (-a * Ax + b * Bx + c * Cx) / (-a + b + c)
        Ja_y = (-a * Ay + b * By + c * Cy) / (-a + b + c)
        Jb_x = (a * Ax - b * Bx + c * Cx) / (a - b + c)
        Jb_y = (a * Ay - b * By + c * Cy) / (a - b + c)
        Jc_x = (a * Ax + b * Bx - c * Cx) / (a + b - c)
        Jc_y = (a * Ay + b * By - c * Cy) / (a + b - c)

        return np.array([Ja_x, Ja_y, 0]), np.array([Jb_x, Jb_y, 0]), np.array([Jc_x, Jc_y, 0])

    def get_incircle_radius(self): # 内切圆半径
        a, b, c = self.get_side_length()
        # 1/2 * (a+b+c) * r = S
        # r = S*2/(a+b+c)
        return self.get_area()*2/(a+b+c)

    def get_incircle(self): # 内切圆                 
        return Circle(radius = self.get_incircle_radius()).move_to(self.get_incenter())

    def get_excircle_radius(self): # 旁切圆半径
        S = self.get_area()
        a, b, c = self.get_side_length()
        return 2*S/(-a+b+c), 2*S/(a-b+c), 2*S/(a+b-c)

    def get_excircle(self): # 旁切圆
        radius_ = self.get_excircle_radius()
        J = self.get_excenter()
        return [Circle(radius = radius_[i]).move_to(J[i]) for i in range(3)]

    def get_circumcircle(self): # 外接圆
        A, B, C = Polygon.get_vertices(self)
        Ax, Ay = A[0], A[1]
        circumcenter = self.get_circumcenter()
        circumradius = math.sqrt((Ax-circumcenter[0])**2 + (Ay-circumcenter[1])**2)
        return Circle(radius = circumradius).move_to(circumcenter)

    def get_O9Circle(self): # 九点圆
        A, B, C = Polygon.get_vertices(self)
        Ax, Ay = A[0], A[1]
        Bx, By = B[0], B[1]
        Cx, Cy = C[0], C[1]
        H = self.get_orthocenter()
        Hx, Hy = H[0], H[1]

        M_a = np.array([(Ax+Hx)/2,(Ay+Hy)/2,0])
        M_b = np.array([(Bx+Hx)/2,(By+Hy)/2,0])
        M_c = np.array([(Cx+Hx)/2,(Cy+Hy)/2,0])

        O9Center = MyTriangle(M_a, M_b, M_c).get_circumcenter()
        O9Radius = math.sqrt((O9Center[0] - M_a[0]) ** 2 + (O9Center[1] - M_a[1]) ** 2)
        return Circle(radius = O9Radius).move_to(O9Center)
    
    def get_O9Center(self): # 九点圆圆心
        return self.get_O9Circle().get_center()

    def get_O9Radius(self): # 九点圆半径
        return self.get_O9Circle().radius

def right_angle(side,corner):
    sq=RegularPolygon(4,fill_opacity=0,stroke_width=2).scale(0.2).set_color(WHITE).rotate(-PI/4)
    sq.next_to(corner,UR,buff=0)
    coor=side-corner
    angle=math.atan2(coor[1],coor[0])
    sq.rotate(angle,about_point=corner)
    return sq

class scene1(Scene):
    def construct(self):
        声明=Text("该视频由manimgl制作，\n\n使用了 @數心 和 @我是害羞的向量 的MyTriangle库").set_width(14)
        self.play(Write(声明))
        self.wait(2)
        self.play(FadeOut(声明))
        triangle=MyTriangle(np.array([-2,-1,0]),np.array([2,-1,0]),np.array([1,2,0]),color=BLUE,fill_opacity=0.5,stroke_width=5)
        self.play(ShowCreation(VGroup(triangle)),run_time=2)
        A=Tex("A").next_to(np.array([-2,-1,0]),DL)
        B=Tex("B").next_to(np.array([2,-1,0]),DR)
        C=Tex("C").next_to(np.array([1,2,0]),UP)
        vg=VGroup(A,B,C)
        self.play(Write(vg))
        l1=Line(np.array([-2,-1,0]),np.array([2,-1,0]))
        l2=Line(np.array([2,-1,0]),np.array([1,2,0]))
        l3=Line(np.array([1,2,0]),np.array([-2,-1,0]))
        self.wait()
        lines=VGroup(l1,l2,l3).set_color(YELLOW)
        for l in lines:
            l.scale(1.1)
        lrestore=lines.copy()
        self.play(*[ShowCreation(l) for l in lines])
        self.wait()
        self.play(*[Rotate(l,PI/2) for l in lines],run_time=2)
        self.wait()

        外心=Dot(triangle.get_circumcenter(),color=RED_B)
        self.play(Write(外心),
                  *[lines[i].animate.put_start_and_end_on(lrestore[i].get_center(),外心.get_center()).set_color(WHITE) for i in range(3)])
        O=Tex("O").next_to(外心,UP)
        self.play(Write(O))
        self.wait()
        circle=triangle.get_circumcircle()
        self.play(TransformFromCopy(外心,circle),FadeOut(lines[1:]))
        
        h1=Line(np.array([-2,-1,0]),np.array([1.6,0.2,0]))
        h2=Line(np.array([2,-1,0]),np.array([0,1,0]))
        h3=Line(np.array([1,2,0]),np.array([1,-1,0]))
        heights=VGroup(h1,h2,h3).set_color(YELLOW)
        垂心=Dot(triangle.get_orthocenter(),color=GREEN)
        H=Tex("H").next_to(垂心,UR)
        self.wait()
        self.play(*[ShowCreation(l) for l in heights])
        self.wait()
        self.play(heights.animate.set_color(WHITE),Write(垂心))
        self.play(Write(H))
        self.wait()
        self.play(FadeOut(h2))

class scene2(Scene):
    def construct(self):
        triangle=MyTriangle(np.array([-2,-1,0]),np.array([2,-1,0]),np.array([1,2,0]),color=BLUE,fill_opacity=0.5,stroke_width=5)
        A=Tex("A").next_to(np.array([-2,-1,0]),DL)
        B=Tex("B").next_to(np.array([2,-1,0]),DR)
        C=Tex("C").next_to(np.array([1,2,0]),UP)
        vg=VGroup(A,B,C)
        l1=Line(np.array([0,-1,0]),np.array([0,0,0]))
        外心=Dot(triangle.get_circumcenter(),color=RED_B)
        O=Tex("O").next_to(外心,UP)
        h1=Line(np.array([-2,-1,0]),np.array([1.6,0.2,0]))
        h3=Line(np.array([1,2,0]),np.array([1,-1,0]))
        heights=VGroup(h1,h3)
        垂心=Dot(triangle.get_orthocenter(),color=GREEN)
        H=Tex("H").next_to(垂心,UR)
        circle=triangle.get_circumcircle()
        self.add(triangle,vg,l1,外心,O,heights,垂心,H,circle)
        self.wait()
        self.play(*[t.animate.set_opacity(0.1) for t in [heights,垂心,H]])
        diameter=Line(np.array([2,-1,0]),np.array([-2,1,0]))
        didown=Line(np.array([-2,1,0]),np.array([-2,-1,0]))
        self.wait()
        self.add(diameter,外心)
        Bp=Tex("B","'").next_to(np.array([-2,1,0]),UL)
        self.play(ShowCreation(diameter),TransformMatchingTex(B.copy(),Bp,path_arc=PI,run_time=2))
        self.play(ShowCreation(didown))

        text1=Text("这是直径").scale(0.5).rotate(diameter.get_angle()+PI).shift(-UP*0.2-RIGHT*0.1)
        self.wait()
        self.play(Write(text1))
        angle1=right_angle(np.array([2,-1,0]),np.array([-2,-1,0]))
        
        arrow1=Arrow(text1.get_center(),angle1.get_center()).set_color(YELLOW)
        self.play(GrowArrow(arrow1),ShowCreation(angle1))
        self.wait()
        def reverse(t):
            return smooth(1-t)
        self.play(GrowFromPoint(arrow1,arrow1.get_end()),FadeIn(text1),rate_func=reverse)
        angle2=right_angle(np.array([2,-1,0]),np.array([0,-1,0]))
        self.wait()
        self.play(ShowCreation(angle2))
        self.wait()
        tri1=Polygon(np.array([2,-1,0]),np.array([0,-1,0]),ORIGIN,fill_opacity=0.5,fill_color=ORANGE)
        self.play(ShowCreation(VGroup(tri1)))
        self.wait()
        self.play(tri1.animate.scale(2,about_point=(np.array([2,-1,0]))))
        self.wait()
        self.play(tri1.animate.scale(0.5,about_point=(np.array([2,-1,0]))),run_time=0.5)
        tex=Tex("a").next_to(l1,LEFT)
        tex2=Tex("2a").next_to(didown,LEFT)
        self.play(Write(tex))
        self.wait(0.5)
        self.play(tri1.animate.scale(2,about_point=(np.array([2,-1,0]))),TransformFromCopy(tex,tex2),run_time=2)
        self.wait(0.5)
        self.play(FadeOut(VGroup(tri1,angle1,angle2)))
        self.wait(1)
        self.play(*[t.animate.set_opacity(1) for t in [heights,垂心,H]])
        self.play(*[t.animate.set_opacity(0.1) for t in [O,外心,tex,diameter,l1]])

class scene3(Scene):
    def construct(self):
        triangle=MyTriangle(np.array([-2,-1,0]),np.array([2,-1,0]),np.array([1,2,0]),color=BLUE,fill_opacity=0.5,stroke_width=5)
        A=Tex("A").next_to(np.array([-2,-1,0]),DL)
        B=Tex("B").next_to(np.array([2,-1,0]),DR)
        C=Tex("C").next_to(np.array([1,2,0]),UP)
        vg=VGroup(A,B,C)
        l1=Line(np.array([0,-1,0]),np.array([0,0,0]))
        外心=Dot(triangle.get_circumcenter(),color=RED_B)
        O=Tex("O").next_to(外心,UP)
        h1=Line(np.array([-2,-1,0]),np.array([1.6,0.2,0]))
        h3=Line(np.array([1,2,0]),np.array([1,-1,0]))
        heights=VGroup(h1,h3)
        垂心=Dot(triangle.get_orthocenter(),color=GREEN)
        H=Tex("H").next_to(垂心,UR)
        circle=triangle.get_circumcircle()
        diameter=Line(np.array([2,-1,0]),np.array([-2,1,0]))
        didown=Line(np.array([-2,1,0]),np.array([-2,-1,0]))
        Bp=Tex("B","'").next_to(np.array([-2,1,0]),UL)
        tex=Tex("a").next_to(l1,LEFT)
        tex2=Tex("2a").next_to(didown,LEFT)
        self.add(triangle,vg,l1,O,heights,H,circle,diameter,didown,Bp,tex,tex2,外心,垂心)
        for t in [O,外心,tex,diameter,l1]:
            t.set_opacity(0.1)
        diup=Line(np.array([-2,1,0]),np.array([1,2,0]))
        self.wait()
        self.play(ShowCreation(diup))
        self.wait()
        angle1=right_angle(np.array([2,-1,0]),np.array([-2,-1,0]))
        angle2=right_angle(np.array([2,-1,0]),np.array([1,-1,0]))
        angle3=right_angle(np.array([-2,1,0]),np.array([1,2,0]))
        angle4=right_angle(np.array([-2,-1,0]),np.array([1.6,0.2,0]))
        #self.add(angle1,angle2,angle3,angle4)
        self.play(TransformFromCopy(diameter,angle1))
        self.wait()
        self.play(ShowCreation(angle2))
        self.wait()
        self.play(TransformFromCopy(diameter,angle3))
        self.wait()
        self.play(ShowCreation(angle4))
        self.wait()
        a=np.array([-2,-1,0])
        b=np.array([-2,1,0])
        c=np.array([1,2,0])
        h=np.array([1,0,0])
        AB=Line(a,b,color=MAROON_A)
        HC=Line(h,c,color=MAROON_A)
        BC=Line(b,c,color=PURPLE_A)
        AH=Line(a,h,color=PURPLE_A)
        #self.add(AB,HC,BC,AH)
        ABHC=Tex("AB'\\parallel HC",tex_to_color_map={"AB'":MAROON_A,"HC":MAROON_A}).move_to(RIGHT*4+UP/2)
        BCAH=Tex("B'C\\parallel AH",tex_to_color_map={"B'C":PURPLE_A,"AH":PURPLE_A}).move_to(RIGHT*4-UP/2)
        self.add(HC,垂心)
        self.play(TransformFromCopy(angle1,AB),TransformFromCopy(angle2,HC))
        self.play(Write(ABHC))
        self.wait()
        self.add(AH,垂心)
        self.play(TransformFromCopy(angle3,BC),TransformFromCopy(angle4,AH))
        self.play(Write(BCAH))
        para=Polygon(a,b,c,h,fill_color=ORANGE,fill_opacity=0.5)
        self.wait()
        self.play(ShowCreation(VGroup(para)))
        self.wait()
        self.add(para,tex2)
        self.play(tex2.next_to,HC,RIGHT,
                  H.next_to,垂心,RIGHT)
        self.remove(AB,HC,BC,AH)
        self.wait()
        self.play(FadeOut(VGroup(para,ABHC,BCAH,angle1,angle3,angle4)))
        self.wait()
        self.play(*[t.animate.set_opacity(1) for t in [外心,O,l1,tex]])
        self.add(h1,垂心)
        self.play(*[t.animate.set_opacity(0.1) for t in [h1,didown,diup]])
        self.wait()
        angle5=right_angle(np.array([2,-1,0]),np.array([0,-1,0]))
        self.play(ShowCreation(angle5))
        self.wait()
        midline=Line(np.array([1,2,0]),np.array([0,-1,0]))
        HO=Line(np.array([1,0,0]),ORIGIN)
        self.add(midline,HO,垂心,外心)
        self.play(ShowCreation(midline),ShowCreation(HO))
        self.wait()
        重心=Dot(triangle.get_centroid(),color=BLUE)
        G=Tex("G").next_to(重心,UP)
        G.save_state()
        self.play(ShowCreation(VGroup(重心)),Write(G),O.next_to,外心,LEFT)
        self.wait()
        frame=self.camera.frame
        self.play(frame.animate.move_to(midline).scale(0.5))
        texp=Tex("b").move_to(tex).shift(RIGHT*0.7)
        tex2p=Tex("2b").move_to(tex2).shift(LEFT*1.2)
        self.play(ReplacementTransform(tex,texp),ReplacementTransform(tex2,tex2p))
        self.wait()
        text=Text("重心").set_height(G.get_height()).next_to(重心,UP)
        self.play(Transform(G,text))
        self.wait()
        self.play(frame.animate.move_to(ORIGIN).set_height(8),
                  G.animate.restore(),
                  *[FadeOut(t) for t in [A,B,C,circle,l1,h1,h3,angle2,angle5,diameter,diup,didown,Bp,midline,texp,tex2p]])
        conclude=Text("三角形的外心、垂心、重心三点共线",t2c={"外心":RED,"垂心":GREEN,"重心":BLUE}).move_to(DOWN*3)
        self.wait()
        self.play(Write(conclude))
        self.wait()
        self.play(FadeOut(conclude))


class scene4(Scene):
    def construct(self):
        triangle=MyTriangle(np.array([-2,-1,0]),np.array([2,-1,0]),np.array([1,2,0]),color=BLUE,fill_opacity=0.5,stroke_width=5)
        外心=Dot(triangle.get_circumcenter(),color=RED_B)
        垂心=Dot(triangle.get_orthocenter(),color=GREEN)
        重心=Dot(triangle.get_centroid(),color=BLUE)
        line1=Line(外心.get_center(),垂心.get_center())
        kw={"color":"#333333"}
        A=Dot(np.array([-2,-1,0]),**kw)
        B=Dot(np.array([2,-1,0]),**kw)
        C=Dot(np.array([1,2,0]),**kw)
        O=Tex("O")
        G=Tex("G")
        H=Tex("H")
        def tri(obj):
            obj.become(MyTriangle(A.get_center(),B.get_center(),C.get_center(),color=BLUE,fill_opacity=0.5,stroke_width=5))
        def out(obj):
            obj.move_to(triangle.get_circumcenter())
        def prep(obj):
            obj.move_to(triangle.get_orthocenter())
        def mid(obj):
            obj.move_to(triangle.get_centroid())
        def Line1(obj):
            obj.put_start_and_end_on(triangle.get_circumcenter(),triangle.get_orthocenter())
        triangle.add_updater(tri)
        外心.add_updater(out)
        垂心.add_updater(prep)
        重心.add_updater(mid)
        line1.add_updater(Line1)
        O.add_updater(lambda obj:obj.next_to(triangle.get_circumcenter(),LEFT))
        H.add_updater(lambda obj:obj.next_to(triangle.get_orthocenter(),RIGHT))
        G.add_updater(lambda obj:obj.next_to(triangle.get_centroid(),UP))
        self.add(A,B,C,triangle,line1,外心,垂心,重心,O,H,G)
        def rc():
            return np.array([rd.uniform(-4,4),rd.uniform(-2,2),0])
        self.wait()
        for i in range(27):
            self.play(A.move_to,rc(),B.move_to,rc(),C.move_to,rc())
        self.wait()
